package br.fbv.compreja.negocio.infra;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import br.fbv.compreja.activity.base.Util;

public abstract class BaseDao {

	private static final String VALUES_LIST = "__VALS__";
	private static final String PRIMARY_KEY = "__PK__";
	private static final String WHERE_CLAUSE = "__WHERE__";
	private static final String COLUMNS_LIST = "__COLS__";
	private static final String TABLE_NAME = "__TB__";
	protected final DataBaseHelper baseHelper;
	private Context context;
	private final static String SQL_COUNT = "SELECT COUNT(__PK__) from __TB__;";
	private final static String SQL_EXISTE = "SELECT COUNT(__PK__) from __TB__ WHERE __PK__ = ?;";
	private final static String SQL_FIND_BY_PK = "SELECT __COLS__ from __TB__ WHERE __PK__ = ?;";
	private final static String SQL_BUSCAR_WHERE = "SELECT __COLS__ from __TB__ WHERE __WHERE__;";
	private final static String SQL_BUSCAR = "SELECT __COLS__ from __TB__;";
	private final static String SQL_INSERIR = "INSERT INTO __TB__ (__COLS__) VALUES (__VALS__);";
	private final static String SQL_UPDATE = "UPDATE __TB__ SET __COLS__ WHERE __WHERE__;";

	protected BaseDao(Context context) {
		baseHelper = new DataBaseHelper(context);
		this.context = context;
	}

	protected Context getContext() {
		return context;
	}

	protected abstract String getReferenceTable();

	protected abstract String getKeyColumn();

	protected String buildListAllQuery() {
		return SQLiteQueryBuilder.buildQueryString(true, getReferenceTable(),
				getTableColumns(), null, null, null, getDefaultOrderBy(), null);
	}

	protected abstract String getDefaultOrderBy();

	public boolean existe(String pk) {
		SQLiteDatabase db = baseHelper.getReadableDatabase();
		String sql = SQL_EXISTE.replace(PRIMARY_KEY, getKeyColumn()).replace(
				TABLE_NAME, getReferenceTable());
		Cursor result = db.rawQuery(sql, new String[] { pk });
		result.moveToNext();
		int qtd = result.getInt(0);
		result.close();
		return qtd > 0;
	}

	protected Map<String, String> findByID(String pk) {
		SQLiteDatabase db = baseHelper.getReadableDatabase();

		Map<String, String> resultado = new HashMap<String, String>();
		String sql = SQL_FIND_BY_PK
				.replace(PRIMARY_KEY, getKeyColumn())
				.replace(TABLE_NAME, getReferenceTable())
				.replace(COLUMNS_LIST,
						Util.arrayToString(getTableColumns(), ","));
		Cursor result = db.rawQuery(sql, new String[] { pk });
		if (result.moveToNext()) {
			String[] columns = getTableColumns();
			for (int i = 0; i < columns.length; i++) {
				resultado.put(columns[i], result.getString(i));
			}
		}
		result.close();
		return resultado;
	}

	protected abstract String[] getTableColumns();

	protected void insert(Map<String, String> map) {
		String[] columns = getTableColumns();
		String insertSQL = SQL_INSERIR.replace(TABLE_NAME, getReferenceTable())
				.replace(COLUMNS_LIST, Util.arrayToString(columns, ","))
				.replace(VALUES_LIST, buildValuesParamString(columns.length));
		SQLiteDatabase db = baseHelper.getWritableDatabase();
		for (int i = 0; i < columns.length; i++) {
			columns[i] = map.get(columns[i]);
		}
		db.execSQL(insertSQL, columns);
	}

	protected void insert(Map<String, String> map, String referenceTable) {

		String[] columns = new String[map.keySet().size()];
		map.keySet().toArray(columns);
		String insertSQL = SQL_INSERIR.replace(TABLE_NAME, referenceTable)
				.replace(COLUMNS_LIST, Util.arrayToString(columns, ","))
				.replace(VALUES_LIST, buildValuesParamString(columns.length));
		SQLiteDatabase db = baseHelper.getWritableDatabase();
		for (int i = 0; i < columns.length; i++) {
			columns[i] = map.get(columns[i]);
		}

		db.execSQL(insertSQL, columns);
	}

	private String buildValuesParamString(int length) {
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < length; i++) {
			if (i > 0) {
				buffer.append(",");
			}
			buffer.append("?");
		}
		return buffer.toString();
	}

	protected Integer getNextIDFor(String tableName, String pkColumn) {
		SQLiteDatabase db = baseHelper.getReadableDatabase();
		Cursor result = db.rawQuery("SELECT max(" + pkColumn + ") FROM "
				+ tableName + "", null);
		result.moveToNext();
		int nextId = result.getInt(0) + 1;
		result.close();
		return nextId;
	}

	protected List<Map<String, String>> consultar(String[] colunms,
			String tableReference, String where, String[] selectionArgs) {
		String queryString = SQL_BUSCAR_WHERE
				.replace(TABLE_NAME, tableReference)
				.replace(COLUMNS_LIST, Util.arrayToString(colunms, ","))
				.replace(WHERE_CLAUSE, where);
		SQLiteDatabase db = baseHelper.getReadableDatabase();
		Cursor result = db.rawQuery(queryString, selectionArgs);
		List<Map<String, String>> listaRetorno = new ArrayList<Map<String, String>>();
		while (result.moveToNext()) {
			Map<String, String> imgMap = new HashMap<String, String>();
			for (int i = 0; i < colunms.length; i++) {
				imgMap.put(colunms[i], result.getString(i));
			}
			listaRetorno.add(imgMap);
		}
		result.close();
		return listaRetorno;
	}

	protected void alterar(Map<String, String> mapCols, String whereClause) {

		String[] cols = buildColumnsArray(mapCols.keySet());
		String[] colsValues = buildColumnsValuesArray(mapCols, cols);

		String updateString = SQL_UPDATE
				.replace(TABLE_NAME, getReferenceTable())
				.replace(COLUMNS_LIST, buildSetColunsClause(cols))
				.replace(WHERE_CLAUSE, whereClause);

		SQLiteDatabase db = baseHelper.getWritableDatabase();
		db.execSQL(updateString, colsValues);
	}

	private String[] buildColumnsValuesArray(Map<String, String> mapCols,
			String[] cols) {
		String[] colsVals = new String[cols.length];
		for (int i = 0; i < colsVals.length; i++) {
			colsVals[i] = mapCols.get(cols[i]);
		}
		return colsVals;
	}

	private String[] buildColumnsArray(Set<String> set) {
		String[] cols = new String[set.size()];
		int i = 0;
		for (String string : set) {
			cols[i] = string;
			i++;
		}
		return cols;
	}

	private String buildSetColunsClause(String[] cols) {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < cols.length; i++) {
			if (i > 0) {
				builder.append(" , ");
			}
			builder.append(cols[i]);
			builder.append(" = ");
			builder.append(" ? ");
		}
		return builder.toString();
	}
}
